package org.apache.solr.ocean;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.apache.commons.io.FileUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.ocean.core.OceanConfig;
import org.apache.solr.ocean.core.Snapshot;
import org.apache.solr.ocean.core.TransactionSystem;
import org.apache.solr.ocean.core.TransactionSystem.Category.Snapshots;
import org.apache.solr.ocean.replication.Replication;
import org.apache.solr.ocean.util.Timeout;
import org.apache.solr.ocean.util.Util;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.util.RefCounted;

/**
 * Maps to an Ocean category
 */
public class OceanCore extends SolrCore {
  private ThreadLocal<Snapshot> threadSnapshot;
  private ThreadLocal<Timeout> threadTimeout;
  private TransactionSystem.Category category;
  private static TransactionSystem transactionSystem;

  public OceanCore(String name, String dataDir, SolrConfig config, IndexSchema schema) {
    super(name, dataDir, config, schema);
    // TODO: get proper name
    // TODO: load category using info from config
    try {
      TransactionSystem transactionSystem = getTransactionSystem();
      category = transactionSystem.loadCategory(name, config);
    } catch (Exception exception) {
      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, exception);
    }
  }

  private TransactionSystem getTransactionSystem() throws Exception {
    synchronized (TransactionSystem.class) {
      if (transactionSystem == null) {
        File oceanConfigFile = new File(getSolrConfig().getInstanceDir(), "oceanconfig.xml");
        OceanConfig oceanConfig = OceanConfig.load(oceanConfigFile);
        int serverNumber = oceanConfig.getServerNumber();
        File rootDirectory = new File(SolrResourceLoader.locateInstanceDir());
        File replicationDirectoryFile = Util.getDirectory(rootDirectory, "replication");
        File idFile = new File(rootDirectory, "id.txt");
        String id = null;
        if (!idFile.exists()) {
          id = UUID.randomUUID().toString();
          FileUtils.writeStringToFile(idFile, id);
        } else {
          id = FileUtils.readFileToString(idFile);
        }
        URL url = oceanConfig.getUrl();
        Replication replication = new Replication(id, serverNumber, url, replicationDirectoryFile, Loader loader, Cell cell);
        transactionSystem = TransactionSystem(oceanConfig, serverNumber, replication, rootDirectory, Loader loader);
      }
    }
    return transactionSystem;
  }

  void initIndex() {
    // do nothing
  }

  public Timeout getThreadTimeout() {
    return threadTimeout.get();
  }

  public Snapshot getThreadSnapshot() {
    Snapshot snapshot = threadSnapshot.get();
    if (snapshot == null) {
      Snapshots snapshots = category.getSnapshots();
      snapshot = snapshots.getLatestSnapshot();
      threadSnapshot.set(snapshot);
    }
    return snapshot;
  }

  public ExecutorService getExecutorService() {
    return category.getTransactionSystem().getCommitThreadPool();
  }

  public TransactionSystem.Category getCategory() {
    return category;
  }

  /**
   * Parameters ignored
   */
  public RefCounted<SolrIndexSearcher> getSearcher(boolean forceNew, boolean returnSearcher, final Future[] waitSearcher)
      throws IOException {
    Snapshot snapshot = getThreadSnapshot();
    OceanSearcher oceanSearcher = new OceanSearcher(snapshot, this);
    RefCounted<SolrIndexSearcher> refCounted = new RefCounted<SolrIndexSearcher>(oceanSearcher) {
      public void close() {
      }
    };
    refCounted.incref();
    return refCounted;
  }
}
